I did the enclosed PDF as part of a personal resource to remind myself about "policy" when writing DXL. It tackles the subject of #include. I find that it is a real trap that '#include' looks for all intents like the C/C++ construct, but (due to the lack of #define mechanisms) really should not be used in the same way that people are used to in C/C++. Anyway, for what its worth (warts 'n' all), here's my mini survival guide to include files.
AlexTidmarsh - Sat Nov 01 08:25:17 EDT 2014 |
Re: Surviving DXL : Surviving File Inclusion I like the approach of getting hard errors for circular defines. Kudos for this :-) However what I normally find is the situation, that you have a couple of core libraries (like stringfunctions.inc or you special datatypes) and you have a lot of higher level libraries using them. This will give you the following problem:
/-> OleFunctions.inc
/ \
StringFunctions.inc \
\ \
\-----------+--> ExcelFunctions.inc
This is a perfectly normal and sane way to structure your libraries, however you cannot handle this situation when you allow libraries to include each other for dependencies. To handle this situation, you cannot use include statements inside the libraries, however starting a DXL script with: #include <StringFunctions.inc> #include <OleFunctions.inc> #include <ExcelFunctions.inc> perfectly works. Therefore I would propose another way of handling includes and prevent circular includes before they even happen. I would put a simple rule:
On top of a library file, I usually do:
// ExcelFunctions.inc - Functions to control Excel over COM / OLE /* Requires:
#include <lib/core/StringFunctions.inc> */ When a .dxl script needs to include the library, then it can just copy/paste the lines above. If it already has other libraries included, then it will just "manually merge" the requirements of that library to the ones at top of the script. This approach is very clean insofar that you will never get circular dependencies and are able to handle the normal structure of libraries. The "drawback" (but this is something that happens in all approaches) is once you start changing a library, you will eventually add a dependency to an existing library, that has already been used in other places. In this case you will need to change ALL scripts that include the library and add the include dependency. However if you have a central code base, that is accessible for each developer this works fast and easy by doing a global search for the library name. You will find it in all libraries that depend on that library (due to the comment) and in all scripts using the library. Then you insert the include dependency in all libraries (on the comment) and on all DXL scripts. Of course you can have exceptions, but these will make your overview go away quickly. Declaring a global variable at the top of each library will also make sure that a library is never included accidentally twice by a script. Hope this helps someone, regards, Mathias
|
Re: Surviving DXL : Surviving File Inclusion Mathias Mamsch - Sun Nov 02 08:05:52 EST 2014 I like the approach of getting hard errors for circular defines. Kudos for this :-) However what I normally find is the situation, that you have a couple of core libraries (like stringfunctions.inc or you special datatypes) and you have a lot of higher level libraries using them. This will give you the following problem:
/-> OleFunctions.inc
/ \
StringFunctions.inc \
\ \
\-----------+--> ExcelFunctions.inc
This is a perfectly normal and sane way to structure your libraries, however you cannot handle this situation when you allow libraries to include each other for dependencies. To handle this situation, you cannot use include statements inside the libraries, however starting a DXL script with: #include <StringFunctions.inc> #include <OleFunctions.inc> #include <ExcelFunctions.inc> perfectly works. Therefore I would propose another way of handling includes and prevent circular includes before they even happen. I would put a simple rule:
On top of a library file, I usually do:
// ExcelFunctions.inc - Functions to control Excel over COM / OLE /* Requires:
#include <lib/core/StringFunctions.inc> */ When a .dxl script needs to include the library, then it can just copy/paste the lines above. If it already has other libraries included, then it will just "manually merge" the requirements of that library to the ones at top of the script. This approach is very clean insofar that you will never get circular dependencies and are able to handle the normal structure of libraries. The "drawback" (but this is something that happens in all approaches) is once you start changing a library, you will eventually add a dependency to an existing library, that has already been used in other places. In this case you will need to change ALL scripts that include the library and add the include dependency. However if you have a central code base, that is accessible for each developer this works fast and easy by doing a global search for the library name. You will find it in all libraries that depend on that library (due to the comment) and in all scripts using the library. Then you insert the include dependency in all libraries (on the comment) and on all DXL scripts. Of course you can have exceptions, but these will make your overview go away quickly. Declaring a global variable at the top of each library will also make sure that a library is never included accidentally twice by a script. Hope this helps someone, regards, Mathias
I love the bit: "... all #include statements shall only be put at the main .dxl file ... " The main could be the code you tie to a menu (effectively as an applet) in which case, there's a lot of mains! Or it could be your batch DXL code when you run DOORS in batch mode. Or of course, it could be the code you use in the -dxl or -C switches that "pre-loads" code when DOORS starts up in interactive mode. To summarize: put the includes at the highest level you can. Preferably all together in one place as a list, so you can easily juggle the inclusion order and so resolve dependencies. And this is basically "upside-down" to what you'd do in C - which was the main point I was making. In the extreme - give serious consideration to the idea of pre-loading all your libraries via the -dxl switch, thus effectively creating an extended set of perms. I also agree entirely with your point about trying to make your libraries (as far as possible) into stand-alone entities. There's a very old adage that was popular 30 years ago: keep your coupling low and your coherence high. That was before someone hijacked it to start Object Orientation. All that said, 90% of the DXL code base of our project comprises getters, setters and event code! So there's no main as such. Which means the only real purpose of "main" would be to pre-load DXL subroutines! Although, to be clear, this is because 90% of the overall code in the project is actually written in Delphi! Delphi then uses DXL as "its bitch". I try to keep the DXL content to the absolute minimum I can get away with politically and technically! This is for reasons of (in no particular order): Retaining My Sanity, Having Code That Actually Works, Having Code That Doesn't Take Forever To Run, Doing Stuff No Sane Person Would Even Attempt In DXL If They Had A Choice. (etc, etc) - And as an added bonus, Delphi can even do maths ;-) Once you've mastered the technique of writing COM servers in Delphi, combined with a "script-server" written in DXL, there's literally no limit to what you can make DOORS do. Anyway, I digress.... |
Re: Surviving DXL : Surviving File Inclusion AlexTidmarsh - Mon Nov 03 16:54:42 EST 2014 I love the bit: "... all #include statements shall only be put at the main .dxl file ... " The main could be the code you tie to a menu (effectively as an applet) in which case, there's a lot of mains! Or it could be your batch DXL code when you run DOORS in batch mode. Or of course, it could be the code you use in the -dxl or -C switches that "pre-loads" code when DOORS starts up in interactive mode. To summarize: put the includes at the highest level you can. Preferably all together in one place as a list, so you can easily juggle the inclusion order and so resolve dependencies. And this is basically "upside-down" to what you'd do in C - which was the main point I was making. In the extreme - give serious consideration to the idea of pre-loading all your libraries via the -dxl switch, thus effectively creating an extended set of perms. I also agree entirely with your point about trying to make your libraries (as far as possible) into stand-alone entities. There's a very old adage that was popular 30 years ago: keep your coupling low and your coherence high. That was before someone hijacked it to start Object Orientation. All that said, 90% of the DXL code base of our project comprises getters, setters and event code! So there's no main as such. Which means the only real purpose of "main" would be to pre-load DXL subroutines! Although, to be clear, this is because 90% of the overall code in the project is actually written in Delphi! Delphi then uses DXL as "its bitch". I try to keep the DXL content to the absolute minimum I can get away with politically and technically! This is for reasons of (in no particular order): Retaining My Sanity, Having Code That Actually Works, Having Code That Doesn't Take Forever To Run, Doing Stuff No Sane Person Would Even Attempt In DXL If They Had A Choice. (etc, etc) - And as an added bonus, Delphi can even do maths ;-) Once you've mastered the technique of writing COM servers in Delphi, combined with a "script-server" written in DXL, there's literally no limit to what you can make DOORS do. Anyway, I digress.... You are of course right, that especially the "script" can be anywhere from layout dxl to attribute dxl, batch, trigger, ... Here you have a special problem:
I see your point regarding the Script Server. A lot of companies use this approach. There are also some open source interfaces to DOORS out there. If your business logic is already in Delphi, of course you can have a large reuse to connect it to DOORS. However for deploying COM Servers company wide there is a certain amount of IT-logistics you need to take care of. Also there are lots of performance issues to take care of (e.g. string table/allocated object leaks if lots of data is transferred through a com server). But: Once you got it working of course it can be a treat. As long as you do not simply "move" the DXL coding to delphi of course ;-) Regards, Mathias |
Re: Surviving DXL : Surviving File Inclusion Mathias Mamsch - Tue Nov 04 10:08:19 EST 2014 You are of course right, that especially the "script" can be anywhere from layout dxl to attribute dxl, batch, trigger, ... Here you have a special problem:
I see your point regarding the Script Server. A lot of companies use this approach. There are also some open source interfaces to DOORS out there. If your business logic is already in Delphi, of course you can have a large reuse to connect it to DOORS. However for deploying COM Servers company wide there is a certain amount of IT-logistics you need to take care of. Also there are lots of performance issues to take care of (e.g. string table/allocated object leaks if lots of data is transferred through a com server). But: Once you got it working of course it can be a treat. As long as you do not simply "move" the DXL coding to delphi of course ;-) Regards, Mathias That's a couple of interesting points I hadn't thought of. I shall have to have a think about their connotations. (a) Attribute DXL is stored in the baseline - (but presumably only if you set the attribute flags that way) (b) Attribute DXL may therefore go with the module to another company Although to be fair, (b) had been recognised - since we had to provide some special DXL to allow suppliers to process the modules. But if these DXL start to depend on "global includes" that that company do not have (especially for reasons of copyright), then some extra care is needed. So thanks for alerting me to this one. Yeh - script server - and I thought I was doing something pretty cool and unique! But then I guess so did the guy who invented the wheel. Like all the other guys at the time who invented the wheel. But at least mine might the only DXL-wheel for Delphi. Ho hum. It's quite shiny too. P.S. Yeh - took care of the COM server logistics very early on. Thankfully, I have IT in my pocket on this. |